package com.vgulu.server.common.BaseDao;

import com.vgulu.server.common.BaseDao.exception.DaoException;
import com.vgulu.server.common.utils.BeanUtil;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangchunsee on 16/1/12.
 */
public abstract class BaseDaoImpl<K,T> implements BaseDao<K,T> {

    //按主键查询
    public static String SELECT_BY_PRIMARY_KEY = "selectByPrimaryKey";
    public static String DELETE_BY_PRIMARY_KEY = "deleteByPrimaryKey";
    public static String INSERT = "insert";
    public static String INSERT_SELECTIVE = "insertSelective";
    public static String UPDATE_BY_PRIMARY_KEY = "updateByPrimaryKey";
    public static String UPDATE_BY_PRIMARY_KEY_SELECTIVE = "updateByPrimaryKeySelective";
    public static String SELECT_COUNT = "selectCount";
    public static String BATCH_INSERT = "batchInsert";
    public static String BATCH_UPDATE = "batchUpdate";
    public static String SELECT = "select";


    private final Logger logger = LoggerFactory.getLogger(BaseDaoImpl.class);

    @Autowired(required = true)
    protected SqlSessionTemplate sqlSessionTemplate;

    protected static final String DOT = ".";

    protected String sqlNameSpace = getSqlNameSpace();

    public abstract String getSqlNameSpace();



    public <V extends T> List<V> selectList(T query, Pageable pageable) {
        return selectList(query,pageable, BaseDaoImpl.SELECT);
    }

    public <V extends T> List<V> selectList(T query, Pageable pageable,String selectId) {
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            Map<String, Object> params = BeanUtil.toMap(query);
           return selectList(params,pageable,selectId);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据分页对象查询列表出错！语句:%s", sqlExecutor), ex);
        }
    }

    public <V extends T> List<V> selectList(Map query, Pageable pageable,String selectId) {
        Map temp = new HashMap(query);
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            if(pageable!=null){
                temp.put("offset",pageable.getOffset());
                temp.put("limit",pageable.getPageSize());
            }
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectList(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据分页对象查询列表出错！语句:%s", sqlExecutor), ex);
        }
    }

    public <V extends T> V selectOne(T query){
        return selectOne(query, BaseDaoImpl.SELECT);
    }

    public <V extends T> V selectOne(T query,String selectId){
        PageRequest page = new PageRequest(0,1);
        List<V> temp = selectList(query,page,selectId);
        if (temp!=null){
            if (temp.isEmpty()){
                return null;
            }else {
                return temp.get(0);
            }
        }
        return null;
    }

    public <V extends T> V selectOne(Map query, String selectId){
        PageRequest page = new PageRequest(0,1);
        List<V> temp = selectList(query,page,selectId);
        if (temp!=null){
            if (temp.isEmpty()){
                return null;
            }else {
                return temp.get(0);
            }
        }
        return null;
    }



    public <V extends T> V selectByPrimaryKey(K id) {
        Assert.notNull(id);
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.SELECT_BY_PRIMARY_KEY;
        try {
            logger.info(sqlExecutor + ":" + id);
            return sqlSessionTemplate.selectOne(sqlExecutor, id);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据ID查询对象出错！语句：%s", sqlExecutor), ex);
        }
    }


    public int selectCount(T query) {
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.SELECT_COUNT;
        try {
            Map<String, Object> params = BeanUtil.toMap(query);
            logger.info(sqlExecutor + ":" + params.toString());
            return sqlSessionTemplate.selectOne(sqlExecutor, params);
        } catch (Exception ex) {
            throw new DaoException(String.format("查询对象总数出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int insert(T entity) {
        Assert.notNull(entity);
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.INSERT;
        try {
            return sqlSessionTemplate.insert(sqlExecutor, entity);
        } catch (Exception ex) {
            throw new DaoException(String.format("添加对象出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int insertSelective(T entity){
        Assert.notNull(entity);
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.INSERT_SELECTIVE;
        try {
            return sqlSessionTemplate.insert(sqlExecutor, entity);
        } catch (Exception ex) {
            throw new DaoException(String.format("添加对象部分字段出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int update(T entity,String selectId){
        Assert.notNull(entity);
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            Map<String, Object> params = BeanUtil.toMap(entity);
            logger.info(sqlExecutor + ":" + params.toString());
            return sqlSessionTemplate.update(sqlExecutor, params);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据主键更新对象全部字段出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int updateByPrimaryKey(T entity) {
        Assert.notNull(entity);
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.UPDATE_BY_PRIMARY_KEY;
        try {
            return sqlSessionTemplate.update(sqlExecutor, entity);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据主键更新对象全部字段出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int updateByPrimaryKeySelective(T entity){
        Assert.notNull(entity);
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.UPDATE_BY_PRIMARY_KEY_SELECTIVE;
        try {
            Map<String, Object> params = BeanUtil.toMap(entity);
            logger.info(sqlExecutor + ":" + params.toString());
            return sqlSessionTemplate.update(sqlExecutor, params);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据主键更新对象部分字段出错！语句：%s", sqlExecutor), ex);
        }
    }

    public int deleteByPrimaryKey(K id) {
        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.DELETE_BY_PRIMARY_KEY;
        try {
            return sqlSessionTemplate.delete(sqlExecutor, id);
        } catch (Exception ex) {
            throw new DaoException(String.format("删除对象出错！语句：%s", sqlExecutor), ex);
        }
    }


    public int batchInsert(List<T> list){
        if(list == null || list.size() == 0) return 0;

        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.BATCH_INSERT;
        try {
            logger.info(sqlExecutor + ":" + list.size());
            return sqlSessionTemplate.insert(sqlExecutor, list);
        } catch (Exception ex) {
            throw new DaoException(String.format("batchInsert：%s", sqlExecutor), ex);
        }
    }

    public int batchUpdate(List<T> list){
        if(list == null || list.size() == 0) return 0;

        String sqlExecutor = sqlNameSpace + DOT + BaseDaoImpl.BATCH_UPDATE;
        try {
            logger.info(sqlExecutor + ":" + list.size());
            return sqlSessionTemplate.update(sqlExecutor, list);
        } catch (Exception ex) {
            throw new DaoException(String.format("batchUpdate：%s", sqlExecutor), ex);
        }
    }

    protected RowBounds getRowBounds(Pageable pageable) {
        RowBounds bounds = RowBounds.DEFAULT;
        if (null != pageable) {
            bounds = new RowBounds(pageable.getOffset(), pageable.getPageSize());
        }

        return bounds;
    }

    protected Map<String, Object> getParams(T query, Pageable pageable) {
        Map<String, Object> params = BeanUtil.toMap(query, getRowBounds(pageable));
        if (pageable != null && pageable.getSort() != null) {
            String sorting = pageable.getSort().toString();
            params.put("sorting", sorting.replace(":", ""));
        }
        return params;
    }

    public List<Map<String,Object>> selectMap(Map query, Pageable pageable, String selectId){
        Map temp = new HashMap(query);
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            if(pageable!=null){
                temp.put("offset",pageable.getOffset());
                temp.put("limit",pageable.getPageSize());
            }
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectList(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据分页对象查询列表出错！语句:%s", sqlExecutor), ex);
        }
    }

    public Map<String,Object> selectOneMap(Map query, String selectId){
        PageRequest page = new PageRequest(0,1);
        List<Map<String,Object>> temp = selectMap(query, page, selectId);
        if (temp!=null){
            if (temp.isEmpty()){
                return null;
            }else {
                return temp.get(0);
            }
        }
        return null;
    }

    public List<Map<String,Object>> selectMap(T query, Pageable pageable, String selectId){
        Map temp = getParams(query,pageable);
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectList(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("根据分页对象查询列表出错！语句:%s", sqlExecutor), ex);
        }
    }

    public Map<String,Object> selectOneMap(T query, String selectId){
        PageRequest page = new PageRequest(0,1);
        List<Map<String,Object>> result = selectMap(query,page,selectId);
        if (result!=null){
            if (result.isEmpty()){
                return null;
            }else {
                return result.get(0);
            }
        }
        return null;
    }

    @Override
    public <V extends T> List<V> select(Map query, String selectId) {
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            Map temp = new HashMap(query);
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectList(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("查询出错！语句:%s", sqlExecutor), ex);
        }
    }

    @Override
    public int selectCount(Map query, String selectId) {
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            Map temp = new HashMap(query);
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectOne(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("查询出错！语句:%s", sqlExecutor), ex);
        }
    }

    @Override
    public List<Map<String, Object>> selectMap(Map query, String selectId) {
        String sqlExecutor = sqlNameSpace + DOT + selectId;
        try {
            Map temp = new HashMap(query);
            logger.info(sqlExecutor + ":" + temp.toString());
            return sqlSessionTemplate.selectList(sqlExecutor, temp);
        } catch (Exception ex) {
            throw new DaoException(String.format("查询出错！语句:%s", sqlExecutor), ex);
        }
    }
}
